#include "stdafx.h"
#include "SomeContainer.h"
#include "Object.h"
#include <atlbase.h>

struct ThreadInfo
{
    CSomeContainer* containter;
    size_t threadIndex;
};

int g_mulValue = 1;
int g_partForRegisterThread = 2;
int g_partForOther = 2;

DWORD WINAPI ThreadFuncRegister(LPVOID ptr)
{
    ThreadInfo* threadInfo = static_cast<ThreadInfo*>(ptr);
    CSomeContainer* containter = threadInfo->containter;
    size_t i = threadInfo->threadIndex * g_partForRegisterThread * g_mulValue;
    size_t maxVal = i + g_partForRegisterThread * g_mulValue;
    for (; i < maxVal; ++i)
    {
        if(!containter->Register(i, boost::shared_ptr<IObject>(new Object(i))))
        {
            // Already exist
            std::cout << "#: " << threadInfo->threadIndex << " " << i << " AE" << std::endl;
        }
    }

    return 0;
}

DWORD WINAPI ThreadFuncQuery(LPVOID ptr)
{
    ThreadInfo* threadInfo = static_cast<ThreadInfo*>(ptr);
    CSomeContainer* containter = threadInfo->containter;

    // comment threadIndex for working with (g_partForOther * g_mulValue) < 2 * (g_partForOther * g_mulValue)
    size_t i = threadInfo->threadIndex * g_partForOther * g_mulValue;
    size_t maxVal = i + g_partForOther * g_mulValue;
    for (; i < maxVal; ++i)
    { 
        boost::shared_ptr<IObject> object = containter->Query(i);
        if(!object.get())
        {
            // Not Query
            std::cout << "#: " << threadInfo->threadIndex << " " << i << " NQ" << std::endl;
        }
    }
    std::cout << std::endl;

    return 0;
}

DWORD WINAPI ThreadFuncUnregister(LPVOID ptr)
{
    ThreadInfo* threadInfo = static_cast<ThreadInfo*>(ptr);
    CSomeContainer* containter = threadInfo->containter;

    // comment threadIndex for working with (g_partForOther * g_mulValue) < 2 * (g_partForOther * g_mulValue)
    size_t i = threadInfo->threadIndex * g_partForOther * g_mulValue;
    size_t maxVal = i + g_partForOther * g_mulValue;
    for (; i < maxVal; ++i)
    { 
        if(!containter->Unregister(i))
        {
            // Not Unregistered
          std::cout << "#: " << threadInfo->threadIndex << " " << i << " NU" << std::endl;
        }
    }
    std::cout << std::endl;

    return 0;
}

DWORD WINAPI ThreadFuncUseIterator(LPVOID ptr)
{
    ThreadInfo* threadInfo = static_cast<ThreadInfo*>(ptr);
    CSomeContainer* containter = threadInfo->containter;
    std::auto_ptr<ISomeContainterIterator> iterator = containter->CreateIterator();

    boost::shared_ptr<IObject> first = iterator->Begin();
    boost::shared_ptr<IObject> last = iterator->End();
    for (; first != last; first = iterator->Next())
    { 
        std::cout << first->Index() << std::endl;
    }
    std::cout << std::endl;

    return 0;
}

int _tmain(int argc, _TCHAR* argv[])
{
    CSomeContainer containter;

    DWORD dwThreadId = 0;

    // create 3 threads for working from 0-40000, 40000-80000, 80000-120000
    ThreadInfo threadInfoRegister1 = {&containter, 0};
    ThreadInfo threadInfoRegister2 = {&containter, 1};
    ThreadInfo threadInfoRegister3 = {&containter, 2};
    ThreadInfo threadInfoRegister4 = {&containter, 3};
    CHandle threadRegister1(CreateThread(NULL, 0, ThreadFuncRegister, &threadInfoRegister1, CREATE_SUSPENDED, &dwThreadId));
    CHandle threadRegister2(CreateThread(NULL, 0, ThreadFuncRegister, &threadInfoRegister2, CREATE_SUSPENDED, &dwThreadId));
    CHandle threadRegister3(CreateThread(NULL, 0, ThreadFuncRegister, &threadInfoRegister3, CREATE_SUSPENDED, &dwThreadId));
    CHandle threadRegister4(CreateThread(NULL, 0, ThreadFuncRegister, &threadInfoRegister4, CREATE_SUSPENDED, &dwThreadId));

    // create 4 threads for working from 0-30000, 30000-60000, 60000-90000, 90000-120000
    ThreadInfo threadInfoQuery1 = {&containter, 0};
    ThreadInfo threadInfoQuery2 = {&containter, 1};
    ThreadInfo threadInfoQuery3 = {&containter, 2};
    ThreadInfo threadInfoQuery4 = {&containter, 3};
    CHandle threadQuery1(CreateThread(NULL, 0, ThreadFuncQuery, &threadInfoQuery1, CREATE_SUSPENDED, &dwThreadId));
    CHandle threadQuery2(CreateThread(NULL, 0, ThreadFuncQuery, &threadInfoQuery2, CREATE_SUSPENDED, &dwThreadId));
    CHandle threadQuery3(CreateThread(NULL, 0, ThreadFuncQuery, &threadInfoQuery3, CREATE_SUSPENDED, &dwThreadId));
    CHandle threadQuery4(CreateThread(NULL, 0, ThreadFuncQuery, &threadInfoQuery4, CREATE_SUSPENDED, &dwThreadId));

    // create 4 threads for working from 0-30000, 30000-60000, 60000-90000, 90000-120000
    ThreadInfo threadInfoUnregister1 = {&containter, 0};
    ThreadInfo threadInfoUnregister2 = {&containter, 1};
    ThreadInfo threadInfoUnregister3 = {&containter, 2};
    ThreadInfo threadInfoUnregister4 = {&containter, 3};
    CHandle threadUnregister1(CreateThread(NULL, 0, ThreadFuncUnregister, &threadInfoUnregister1, CREATE_SUSPENDED, &dwThreadId));
    CHandle threadUnregister2(CreateThread(NULL, 0, ThreadFuncUnregister, &threadInfoUnregister2, CREATE_SUSPENDED, &dwThreadId));
    CHandle threadUnregister3(CreateThread(NULL, 0, ThreadFuncUnregister, &threadInfoUnregister3, CREATE_SUSPENDED, &dwThreadId));
    CHandle threadUnregister4(CreateThread(NULL, 0, ThreadFuncUnregister, &threadInfoUnregister4, CREATE_SUSPENDED, &dwThreadId));

    ThreadInfo threadInfoUseIterator1 = {&containter, 0};
    CHandle threadUseIterator1(CreateThread(NULL, 0, ThreadFuncUseIterator, &threadInfoUseIterator1, CREATE_SUSPENDED, &dwThreadId));

    // register
    ResumeThread(threadRegister1);
    ResumeThread(threadRegister2);
    ResumeThread(threadRegister3);
    ResumeThread(threadRegister4);


    //query
    ResumeThread(threadQuery1);
    ResumeThread(threadQuery2);
    ResumeThread(threadQuery3);
    ResumeThread(threadQuery4);


    //unregister
    // uncomment for using unregistered, but 
    // using iterator will be empty
    ResumeThread(threadUnregister1);
    ResumeThread(threadUnregister2);
    ResumeThread(threadUnregister3);
    ResumeThread(threadUnregister4);

    WaitForSingleObject(threadUnregister1, INFINITE);
    WaitForSingleObject(threadUnregister2, INFINITE);
    WaitForSingleObject(threadUnregister3, INFINITE);
    WaitForSingleObject(threadUnregister4, INFINITE);

    WaitForSingleObject(threadRegister1, INFINITE);
    WaitForSingleObject(threadRegister2, INFINITE);
    WaitForSingleObject(threadRegister3, INFINITE);
    WaitForSingleObject(threadRegister4, INFINITE);


    WaitForSingleObject(threadQuery1, INFINITE);
    WaitForSingleObject(threadQuery2, INFINITE);
    WaitForSingleObject(threadQuery3, INFINITE);
    WaitForSingleObject(threadQuery4, INFINITE);

    // using iterators for showing values
    ResumeThread(threadUseIterator1);
    WaitForSingleObject(threadUseIterator1, INFINITE);

    return 0;
}